import codecs
import pickle as pkl
import os
import time

from web.app.similarity_calculation import SimilarityCalculation

# 全部数据文件
data_file_all = r'/home/ubuntu/data/web/app/dictionary/data_all.txt'


# TODO 数据文件按预定格式读取后序列化保存


class SimilarityRanking(object):
    def __init__(self, data_file='', top_k=100):
        # if data_file and os.path.isfile(data_file):
        #     with open(data_file, 'rb') as f:
        #         self.data_dic = pkl.load(f)
        # else:
        #     self.data_dic = None
        self.sim_cal = SimilarityCalculation()
        s_time = time.clock()
        self.data_dic = self._parsing_data(data_file)
        e_time = time.clock()
        print('loading data costs: {0}s'.format(e_time - s_time))
        self.top_k = top_k

    # 解析全部数据，做成字典, 键是每条数据的序号
    # patient_id, sex, age, height,	weight,	inquiry_sheet, tongue_picture,
    # tongue_feature, tongue_description, report, diagnosis, herbs
    def _parsing_data(self, data_file):
        data_dict_all = {}
        with codecs.open(data_file, "r", encoding='utf-8') as fr:
            key_num = -1
            for line in fr.readlines()[1:]:
                key_num += 1
                value_list = [item.strip() for item in line.strip().split("\t")]
                basic_info = value_list[1:5]
                report = self.sim_cal.report_to_word(value_list[9])
                inquiry_sheet, inquiry_special = self.sim_cal.parse_custom_inquiry(value_list[5])
                tongue_feature = value_list[7]
                tongue_picture = value_list[6]
                diagnosis = value_list[-2]
                herbs = value_list[-1]
                report_orginal = value_list[9]
                data_dict_all[key_num] = [basic_info, report, inquiry_sheet,
                                          tongue_feature, inquiry_special, tongue_picture, diagnosis, herbs,
                                          report_orginal]
        return data_dict_all

    # 返回所有结果
    def retrieval(self, basic_info, report, inquiry_sheet, tongue_feature):
        if self.data_dic is None:
            return None
        # start = time.time()
        report = self.sim_cal.report_to_word(report)
        inquiry_sheet, inquiry_special = self.sim_cal.parse_custom_inquiry(inquiry_sheet)
        # print(inquiry_sheet)
        sim_id_list = self._get_top_k_ids(basic_info, report, inquiry_sheet, tongue_feature)  # 得到的排序结果
        # end = time.time()
        # print("calculation:", end - start)
        res_list = []
        for tid, sim in sim_id_list:
            sim = '%.2f' % sim
            source_data = self.data_dic[tid]
            sim_bi = self.sim_cal.basic_info_distance(basic_info, source_data[0])
            sim_bi = '%.2f' % sim_bi
            sim_report = self.sim_cal.self_statement_distance(report, source_data[1])
            sim_report = '%.2f' % sim_report
            # TODO add same report word list
            # 主诉的拆分
            report_list = self.sim_cal.report_display(report, source_data[1])
            report_same = report_list["report_same"]
            report_same = self._util(report_same)
            target_remain = report_list["target_remain"]
            target_remain = self._util(target_remain)
            source_remain = report_list["source_remain"]
            source_remain = self._util(source_remain)
            # 问诊单相似度
            sim_inquiry = self.sim_cal.inquiry_distance(inquiry_sheet, source_data[2])
            # 问诊单拆分
            inquiry_list = self.sim_cal.inquiry_display(inquiry_sheet, inquiry_special, source_data[2], source_data[4])
            # 异常相同问题
            abnormal_same_inquiry = inquiry_list["abnormal_same"]
            abnormal_same_inquiry_str = ""
            if len(abnormal_same_inquiry) == 0:
                abnormal_same_inquiry_str = "NULL"
            else:
                for i in abnormal_same_inquiry:
                    abnormal_same_inquiry_str += "*@*".join(i)
                    abnormal_same_inquiry_str += "*@*"
                abnormal_same_inquiry_str = abnormal_same_inquiry_str.rstrip("*@*")
            # 异常不同问题
            normal_diff_inquiry = inquiry_list["normal_diff"]
            normal_diff_inquiry_str = self._util_02(normal_diff_inquiry)
            # if len(normal_diff_inquiry) == 0:
            #     normal_diff_inquiry_str = "NULL"
            # else:
            #     for i in normal_diff_inquiry:
            #         normal_diff_inquiry_str += "*@*".join(i)
            #         normal_diff_inquiry_str += "*@*"
            #     normal_diff_inquiry_str = normal_diff_inquiry_str.rstrip("*@*")
            # 原始数据中遗留的问题选项
            target_remain_inquiry = inquiry_list["target_remain"]
            target_remain_inquiry_str = self._util(target_remain_inquiry)
            # 正常相同
            normal_same_inquiry = inquiry_list["normal_same"]
            normal_same_inquiry_str = self._util_02(normal_same_inquiry)
            # 新患者数据中遗留的问题选项
            source_remain_inquiry = inquiry_list["source_remain"]
            source_remain_inquiry_str = self._util(source_remain_inquiry)
            # 舌照相似度
            sim_tongue = self.sim_cal.tongue_distance(tongue_feature, source_data[3])
            # 舌照特征对比结果拆分
            tongue_list = self.sim_cal.tongue_contrast(tongue_feature, source_data[3])
            if len(tongue_list) == 0:
                same_feature_str = "NULL"
                different_feature_str = "NULL"
                same_normal_str = "NULL"
            else:
                same_feature = tongue_list["same_feature"]
                same_feature_str = self._util_02(same_feature)
                different_feature = tongue_list["different_feature"]
                different_feature_str = self._util_02(different_feature)
                same_normal = tongue_list["same_normal"]
                same_normal_str = self._util_02(same_normal)
            # 返回的全部结果
            # if source_data[0][1] == "0.0":
            #     source_data[0][1] = "女"
            # elif source_data[0][1] == "1.0":
            #     source_data[0][1] = "男"
            # source_data_change = "%s" % (source_data[0])
            bi_str = ''
            if source_data[0][0] == 'NULL':
                bi_str += 'NULL,'
            elif source_data[0][0] == '0':
                bi_str += '男,'
            else:
                bi_str += '女,'
            bi_str += ','.join(source_data[0][1:])
            res_list.append({'id': "%s" % tid,
                             'total_sim': "%s" % sim,
                             'basic_info_sim': "%s" % sim_bi,
                             'report_sim': "%s" % sim_report,
                             'report_same': report_same,
                             'target_remain': target_remain,
                             'source_remain': source_remain,
                             'inquiry_sim': "%s" % sim_inquiry,
                             'abnormal_same_inquiry': abnormal_same_inquiry_str,
                             'normal_diff_inquiry': normal_diff_inquiry_str,
                             "normal_same": normal_same_inquiry_str,
                             'target_remain_inquiry': target_remain_inquiry_str,
                             'source_remain_inquiry': source_remain_inquiry_str,
                             'tongue_sim': sim_tongue,
                             'same_feature': same_feature_str,
                             'different_feature': different_feature_str,
                             'same_normal': same_normal_str,
                             'tongue_pic': "%s" % (source_data[5]),
                             "herbs": "%s" % (source_data[7]),
                             "diagnosis": "%s" % (source_data[6]),
                             "basic_info": bi_str,
                             "report": source_data[8],
                             })
        return res_list

    @staticmethod
    def _util(target_list):
        if len(target_list) == 0:
            target_str = "NULL"
        else:
            target_str = "*@*".join(target_list)
        return target_str

    @staticmethod
    def _util_02(double_list):
        target_str = ""
        if len(double_list) == 0:
            target_str = "NULL"
        else:
            for i in double_list:
                target_str += "*@*".join(i)
                target_str += "*@*"
            target_str = target_str.rstrip("*@*")
        return target_str

    # 遍历一次数据集，获取相似度最高的top k个病历id及对应相似度值
    def _get_top_k_ids(self, basic_info, report, inquiry_sheet, tongue_feature):
        sim_list = []
        idx = 0
        for k, v in self.data_dic.items():
            patient_info_01 = [v[0], v[1], v[2], v[3]]
            patient_info_02 = [basic_info, report, inquiry_sheet, tongue_feature]
            temp_sim = self.sim_cal.similarity_result(patient_info_01, patient_info_02)
            # print(temp_sim)
            sim_list.append((k, temp_sim))
            idx += 1
            if idx % 5000 == 0:
                print(idx)
        print('traverse finished')

        sim_list = sorted(sim_list, key=lambda data: data[1], reverse=True)
        sim_res = sim_list
        if len(sim_res) > self.top_k:
            sim_res = sim_list[:self.top_k]
        return sim_res

    def temp_test(self):
        basic_info = ['1', '20', '157', '45']
        report = self.sim_cal.report_to_word('复诊：后背不痒了 手臂也不痒了 但是感觉在分泌油脂 有小颗粒')
        inquiry_sheet = ('您身体的冷热感受如何？（可多选）##怕冷@@您的出汗情况如何？（可多选）##出汗正常@@'
                         '您的身体是否有疼痛？（可多选）##胸痛$$腰痛$$肩颈痛$$肌肉痛$$关节痛$$周身疼痛@@'
                         '您的身体除疼痛外，是否还有以下不适？（可多选）##头晕$$胃胀$$腹胀$$手脚常年冰凉@@'
                         '您的眼部是否有不适？（可多选）##眼睛胀痛$$眼角红赤$$眼部充血$$眼部瘙痒@@'
                         '您的耳部是否有不适？（可多选）##无耳部不适@@您的口部是否有不适？（可多选）##口臭$$嘴唇干裂'
                         '@@您的咽喉是否有不适？（可多选）##无咽喉不适@@您是否有咳嗽喘痰等症状？（可多选）##'
                         '无咳嗽喘痰@@您的睡眠情况如何？（可多选）##多梦$$易醒@@您的口渴及饮水情况如何？（可多选）'
                         '##很少口渴$$喜喝凉水@@您的大便频率如何？##大便每天或隔天一次@@您的大便性状如何？（可多选）'
                         '##大便粘稠@@您的大便颜色如何？##大便呈黑色@@您的小便频率及尿量如何？（可多选）##'
                         '小便频率正常@@您的小便色质如何？（可多选）##小便黄@@您现在是否处于以下特殊阶段？##'
                         '非特殊阶段@@您的生育情况如何？##未生育@@您的流产情况如何？##未曾流产@@您的月经是否规律？'
                         '##月经提前@@您的月经经量是否正常？##经量正常@@您的月经经色、经质如何？（可多选）##'
                         '经血暗红$$经血中有血块@@您的白带情况是否正常？（可多选）##白带量多$$白带有腥臭味$$阴部瘙痒')
        inquiry_sheet, _, _ = self.sim_cal.parse_custom_inquiry(inquiry_sheet)
        tongue_feature = '3,0,1.33,2.67,3.33,0,0,0,0.33,0,2,3,4,0,1'
        test_record = self.data_dic[10]
        print(test_record)
        temp_sim = self.sim_cal.similarity_result([basic_info, inquiry_sheet, report, tongue_feature],
                                                  [test_record[0], test_record[2], test_record[1], test_record[3]])
        print(temp_sim)


def temp_test():
    sim_cal = SimilarityCalculation()
    basic_info = ['1', '20', '157', '45']
    report = sim_cal.report_to_word('复诊：后背不痒了 手臂也不痒了 但是感觉在分泌油脂 有小颗粒')
    inquiry_sheet = ('您身体的冷热感受如何？（可多选）##怕冷@@您的出汗情况如何？（可多选）##出汗正常@@'
                     '您的身体是否有疼痛？（可多选）##胸痛$$腰痛$$肩颈痛$$肌肉痛$$关节痛$$周身疼痛@@'
                     '您的身体除疼痛外，是否还有以下不适？（可多选）##头晕$$胃胀$$腹胀$$手脚常年冰凉@@'
                     '您的眼部是否有不适？（可多选）##眼睛胀痛$$眼角红赤$$眼部充血$$眼部瘙痒@@'
                     '您的耳部是否有不适？（可多选）##无耳部不适@@您的口部是否有不适？（可多选）##口臭$$嘴唇干裂'
                     '@@您的咽喉是否有不适？（可多选）##无咽喉不适@@您是否有咳嗽喘痰等症状？（可多选）##'
                     '无咳嗽喘痰@@您的睡眠情况如何？（可多选）##多梦$$易醒@@您的口渴及饮水情况如何？（可多选）'
                     '##很少口渴$$喜喝凉水@@您的大便频率如何？##大便每天或隔天一次@@您的大便性状如何？（可多选）'
                     '##大便粘稠@@您的大便颜色如何？##大便呈黑色@@您的小便频率及尿量如何？（可多选）##'
                     '小便频率正常@@您的小便色质如何？（可多选）##小便黄@@您现在是否处于以下特殊阶段？##'
                     '非特殊阶段@@您的生育情况如何？##未生育@@您的流产情况如何？##未曾流产@@您的月经是否规律？'
                     '##月经提前@@您的月经经量是否正常？##经量正常@@您的月经经色、经质如何？（可多选）##'
                     '经血暗红$$经血中有血块@@您的白带情况是否正常？（可多选）##白带量多$$白带有腥臭味$$阴部瘙痒')
    inquiry_sheet, _, _ = sim_cal.parse_custom_inquiry(inquiry_sheet)
    tongue_feature = '3,0,1.33,2.67,3.33,0,0,0,0.33,0,2,3,4,0,1'
    temp_sim = sim_cal.similarity_result([basic_info, inquiry_sheet, report, tongue_feature],
                                         [basic_info, inquiry_sheet, report, tongue_feature])
    print(temp_sim)


if __name__ == '__main__':
    similarity_ranking = SimilarityRanking(data_file_all)
    result = similarity_ranking.retrieval(['1', '20', '157', '45'],
                                          '复诊：后背不痒了 手臂也不痒了 但是感觉在分泌油脂 有小颗粒',
                                          '您身体的冷热感受如何？（可多选）##怕冷@@您的出汗情况如何？（可多选）##出汗正常@@'
                                          '您的身体是否有疼痛？（可多选）##胸痛$$腰痛$$肩颈痛$$肌肉痛$$关节痛$$周身疼痛@@'
                                          '您的身体除疼痛外，是否还有以下不适？（可多选）##头晕$$胃胀$$腹胀$$手脚常年冰凉@@'
                                          '您的眼部是否有不适？（可多选）##眼睛胀痛$$眼角红赤$$眼部充血$$眼部瘙痒@@'
                                          '您的耳部是否有不适？（可多选）##无耳部不适@@您的口部是否有不适？（可多选）##口臭$$嘴唇干裂'
                                          '@@您的咽喉是否有不适？（可多选）##无咽喉不适@@您是否有咳嗽喘痰等症状？（可多选）##'
                                          '无咳嗽喘痰@@您的睡眠情况如何？（可多选）##多梦$$易醒@@您的口渴及饮水情况如何？（可多选）'
                                          '##很少口渴$$喜喝凉水@@您的大便频率如何？##大便每天或隔天一次@@您的大便性状如何？（可多选）'
                                          '##大便粘稠@@您的大便颜色如何？##大便呈黑色@@您的小便频率及尿量如何？（可多选）##'
                                          '小便频率正常@@您的小便色质如何？（可多选）##小便黄@@您现在是否处于以下特殊阶段？##'
                                          '非特殊阶段@@您的生育情况如何？##未生育@@您的流产情况如何？##未曾流产@@您的月经是否规律？'
                                          '##月经提前@@您的月经经量是否正常？##经量正常@@您的月经经色、经质如何？（可多选）##'
                                          '经血暗红$$经血中有血块@@您的白带情况是否正常？（可多选）##白带量多$$白带有腥臭味$$阴部瘙痒',
                                          '3,0,1.33,2.67,3.33,0,0,0,0.33,0,2,3,4,0,1'
                                          )
    print(result)
